import inspect

from pydantic import conint

from common.base.base_api import BaseApi
from common.utils import make_literal
from services.dsp.model import Dsp
from services.dsp.schemas.configs import DspConfig, Delays, DspSubchannelsControl, DspModesConfig
from settings import settings

_DSM_MODEL = Dsp()
_CONFIGS_LITERAL = make_literal(_DSM_MODEL.configs)
_COE_LITERAL = make_literal(_DSM_MODEL.coe_configs)
_COE_FILE_LITERAL = make_literal(_DSM_MODEL.coe_files)
_CALIBRATION_TYPE_LITERAL = make_literal(['fsr_link_1', 'fsr_link_2', 'fsc'])


class DspApi(BaseApi):
    __slots__ = []

    def __init__(self):
        super(DspApi, self).__init__(request_queue_uuid=settings.DSP_REQUEST_QUEUE)

    async def set_pilots_cycles(self, cycles: int):
        await self.send_rpc_request_message(inspect.currentframe().f_code.co_name,{'cycles': cycles})

    async def get_pilots_cycles(self) -> int:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name)

    async def get_lo(self) -> list | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name)

    async def get_reinit(self) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name)

    async def set_lo(self, value: float, index: int) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'value': value, 'index': index}
        )

    async def set_reinit(self) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name)

    async def set_dsp_config(self, name: _CONFIGS_LITERAL, config: DspConfig, do_reinit=True) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'name': name, 'config': config.dict(), 'do_reinit': do_reinit}
        )

    async def set_dsp_modes(self, modes: DspModesConfig) -> bool | None:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, modes.dict())

    async def set_typical_coe(self, name: _COE_LITERAL, index: conint(ge=1, le=4), file_name: _COE_FILE_LITERAL
                        ) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'name': name, 'index': index, 'file_name': file_name}
        )

    async def set_custom_hex_coe(self, name: _COE_LITERAL, index: conint(ge=1, le=4), offset_bw_bands: int
                           ) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'name': name, 'index': index, 'offset_bw_bands': offset_bw_bands}
        )

    async def set_channels_control(self, index: conint(ge=0, le=1), control: DspSubchannelsControl
                             ) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'index': index, 'control': control.dict()}
        )

    async def set_delays_config(self, delays: Delays) -> bool | None:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, delays.dict())

    async def get_dsp_config(self, name: _CONFIGS_LITERAL) -> DspConfig | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'name': name},
            handle_result=lambda result: DspConfig(**result)
        )

    async def get_dsp_modes(self) -> DspModesConfig | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            handle_result=lambda result: DspModesConfig(**result)
        )

    async def get_coe(self, name: _COE_LITERAL, index: conint(ge=1, le=4)) -> str | None:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, {'name': name, 'index': index})

    async def get_channels_control(self, index: conint(ge=0, le=1)) -> DspSubchannelsControl | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'index': index},
            handle_result=lambda result: DspSubchannelsControl(**result)
        )

    async def disable_calibration_config(self) -> bool | None:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name)

    async def enable_calibration_config(self, calibration_type: _CALIBRATION_TYPE_LITERAL) -> bool | None:
        return await self.send_rpc_request_message(
            inspect.currentframe().f_code.co_name,
            {'calibration_type': calibration_type}
        )

    async def calc_adfreq_subch_offsets(self, nb_subchannels2: dict, nb_subchannels3: dict, mode: str, max_arfsn: int, min_arfsn: int, service_2_state: bool, service_3_state: bool) -> bool | None:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, {
            'nb_subchannels2': nb_subchannels2,
            'nb_subchannels3': nb_subchannels3,
            'mode': mode,
            'max_arfsn': max_arfsn,
            'min_arfsn': min_arfsn,
            'service_2_state': service_2_state,
            'service_3_state': service_3_state
        })

    async def set_simulation_of_chain(self, state: bool) -> bool:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, {'state': state})

    async def get_simulation_of_chain(self) -> bool:
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name)

    async def set_pilot_freq(self, index: int, freq_rx: int, freq_tx: int):
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, {
            'index': index,
            'freq_rx': freq_rx,
            'freq_tx': freq_tx
        })

    async def get_pilot_freq(self, index: int) -> (int, int):
        return await self.send_rpc_request_message(inspect.currentframe().f_code.co_name, {'index': index})


